package com.ayz.gateway.core.core.Netty;

import cn.hutool.log.Log;

import com.ayz.gateway.core.authorization.IAuth;
import com.ayz.gateway.core.context.config.Configuration;
import com.ayz.gateway.core.core.common.RemotingUtils;
import com.ayz.gateway.core.session.GatewaySessionFactory;
import com.ayz.gateway.server.RemotingServer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import lombok.Data;


import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName NettySessionServer
 * @Description TODO: 以Netty实现的会话
 * @Author 快乐的星球
 * @Date 2023/5/5 16:47
 * @Version 1.0
 **/
@Data
public class NettyGatewayServer implements RemotingServer {
    /**
     * Netty服务端的配置
     */
    private NettyServerConfig serverConfig;
    /**
     * 日志打印
     */
    private Log log=Log.get(NettyGatewayServer.class);

    /**
     * BOSS组
     */
    private EventLoopGroup boss;

    /**
     * worker组
     */
    private EventLoopGroup worker;
    /**
     * 监听的端口号
     */
    private int port;

    /**
     * 当前这个是Netty的并发事件执行组
     */
    private DefaultEventExecutorGroup defaultEventExecutorGroup;

    /**
     * 服务端的Channel
     */
    private ServerSocketChannel serverSocketChannel;
    /**
     * 贯穿整个网关上下文的配置参数
     */
    private Configuration configuration;
    /**
     * 上下文单例的 网关会话工厂
     */
    private GatewaySessionFactory gatewaySessionFactory;
    /**
     * 网关网络层的鉴权模块的鉴权服务类
     */
    private IAuth authService;

    public NettyGatewayServer(NettyServerConfig serverConfig, Configuration configuration, GatewaySessionFactory gatewaySessionFactory, IAuth authService) {
        this.gatewaySessionFactory=gatewaySessionFactory;
        this.configuration=configuration;
        this.serverConfig = serverConfig;
        this.port=serverConfig.getListenPort();
        this.boss=new NioEventLoopGroup(serverConfig.getEventLoopGroupBossThreads(),
                new ThreadFactory() {
                    private final AtomicInteger threadIndex=new AtomicInteger();
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r,"ServerBossThread_"+threadIndex.getAndIncrement());
                    }
                });
        this.worker=new NioEventLoopGroup(serverConfig.getEventLoopGroupWorkerThreads(),
                new ThreadFactory() {
                    private final AtomicInteger threadIndex=new AtomicInteger();
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r,"ServerWorkerThread_"+threadIndex.getAndIncrement());
                    }
                });
        this.defaultEventExecutorGroup=new DefaultEventExecutorGroup(serverConfig.getServerWorkerThreads(),
                new ThreadFactory() {
                    private final AtomicInteger threadIndex=new AtomicInteger();
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r,"NettyServerWorkerThread_"+threadIndex.getAndIncrement());
                    }
                });

        this.authService=authService;
    }

    @Override
    public int getListenPort() {
        return this.port;
    }

    /**
     * 完成Netty服务端的启动
     */
    @Override
    public void start() throws Exception{
        ServerBootstrap serverBootstrap=new ServerBootstrap();
        ChannelFuture channelFuture = serverBootstrap.group(boss, worker)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_KEEPALIVE, false)//默认关闭TCP的心跳
                .option(ChannelOption.SO_BACKLOG, getServerConfig().getNioSoBackLog())
                .option(ChannelOption.SO_REUSEADDR, true)
                //请注意 这里需要判断一下是否处于linux环境下，linux环境默认使用 Epoll
                .channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
                .childHandler(new GatewayChannelInitializer(this))
                .bind(getServerConfig().getListenPort());
        try {
            this.serverSocketChannel =(ServerSocketChannel) channelFuture.sync().channel();
        } catch (InterruptedException e) {
            throw new RuntimeException("NettySessionServer 启动失败;监听的端口号为:{"+getListenPort()+"}");
        }
    }

    /**
     * 判断是否要使用Epoll多路复用器
     * 默认在Linux环境下且配置参数配置了使用Epoll且此时Epoll是可用的就会使用Epoll
     * @return
     */
    protected boolean useEpoll(){
        return RemotingUtils.isLinuxPlatform()
                && getServerConfig().isUseEpollWhenUseLinux()
                && Epoll.isAvailable();
    }

    /**
     * 网关远程通信组件的关闭
     */
    @Override
    public void shutdown() {
        log.info("NettySessionServer shutdown;listenPort:{"+getListenPort()+"}");
        if(boss!=null){
            boss.shutdownGracefully();
        }
        if(worker!=null){
            worker.shutdownGracefully();
        }
        if(defaultEventExecutorGroup!=null){
            defaultEventExecutorGroup.shutdownGracefully();
        }
    }
}
